﻿namespace SharePoint.ImportExport.Core
{
    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.IO;
    using System.Xml.Serialization;

    /// <summary>
    /// The FieldType enumeration specifies a field type for a field.
    /// </summary>
    public enum FieldType
    {
        /// <summary>
        /// Specifies an all day event.
        /// </summary>
        AllDayEvent,

        /// <summary>
        /// Contains attachments.
        /// </summary>
        Attachments,

        /// <summary>
        /// Contains Boolean values that are stored in the database as 1 or 0.
        /// </summary>
        Boolean,

        /// <summary>
        /// Contains calculated values.
        /// </summary>
        Calculated,

        /// <summary>
        /// Specifies a predetermined set of values that can be used to enter data into the field.
        /// </summary>
        Choice,

        /// <summary>
        /// Specifies an abstract field type that depends on other fields for its content and definition.
        /// </summary>
        Computed,

        /// <summary>
        /// Contains an integer used for internal ID fields. 
        /// </summary>
        Counter,

        /// <summary>        
        /// Specifies a link between projects in a Meetings Workspace site.
        /// </summary>
        CrossProjectLink,

        /// <summary>
        /// Contains currency values formatted based on a specific locale.
        /// </summary>
        Currency,

        /// <summary>
        /// Contains date and time values. 
        /// </summary>
        DateTime,

        /// <summary>
        /// Contains errors.  
        /// </summary>
        Error,

        /// <summary>
        /// Contains files.  
        /// </summary>
        File,

        /// <summary>
        /// Specifies a Choice field for a data sheet.  
        /// </summary>
        GridChoice,

        /// <summary>
        /// Contains GUIDs.  
        /// </summary>
        Guid,

        /// <summary>
        /// Contains positive or negative integer values.
        /// </summary>
        Integer,

        /// <summary>
        /// Non valid entity
        /// </summary>
        Invalid,

        /// <summary>
        /// Contains references to values in other lists. 
        /// </summary>
        Lookup,

        /// <summary>
        /// Contains the maximum number of items.
        /// </summary>
        MaxItems,

        /// <summary>
        /// Specifies Content Approval status.
        /// </summary>
        ModStat,

        /// <summary>
        /// Contains multiple values per list item.
        /// </summary>
        MultiChoice,

        /// <summary>
        /// Specifies a field that can contain multiple lines of text. 
        /// </summary>
        Note,

        /// <summary>
        /// Contains floating point numbers. 
        /// </summary>
        Number,

        /// <summary>
        /// Specifies a field used in calendars for recurring events and, like computed fields, an abstract field type that depends on other fields for its content and definition. 
        /// </summary>
        Recurrence,

        /// <summary>
        /// Contains a single line of text.
        /// </summary>
        Text,

        /// <summary>
        /// Specifies a field that is used in the creation and display of threaded Web discussions. 
        /// </summary>
        Threading,

        /// <summary>
        /// Contains hyperlinks. 
        /// </summary>
        URL,

        /// <summary>
        /// Specifies users of a SharePoint site. 
        /// </summary>
        User,

        /// <summary>
        /// Specifies multiple users of a SharePoint site. 
        /// </summary>
        UserMulti,

        /// <summary>
        /// Contains the status of the workflow
        /// </summary>
        WorkflowStatus,

        /// <summary>
        /// Contains a field of type image
        /// </summary>
        Image,

        /// <summary>
        /// This is the start date of for publishing
        /// </summary>
        PublishingScheduleStartDateFieldType,

        /// <summary>
        /// This is the start date of for publishing
        /// </summary>
        PublishingScheduleEndDateFieldType,

        /// <summary>
        /// This is the targetting info
        /// </summary>
        TargetTo,

        /// <summary>
        /// HTML type
        /// </summary>
        HTML,

        /// <summary>
        /// Summary Links
        /// </summary>
        SummaryLinks,

        /// <summary>
        /// Multi value lookup
        /// </summary>
        LookupMulti,

        /// <summary>
        /// Taxonomy field
        /// </summary>
        TaxonomyFieldType,	

            /// <summary>
        /// Multi value Taxonomy field
        /// </summary>
        TaxonomyFieldTypeMulti,
        
        /// <summary>
        /// ChannelAliasfieldType
        /// </summary>
        ChannelAliasFieldType,
        
        /// <summary>
        /// Likes field types
        /// </summary>
        Likes,
        
        /// <summary>
        /// Average rating field type
        /// </summary>
        AverageRating,

        /// <summary>
        /// RatingCount field type
        /// </summary>
        RatingCount,

        /// <summary>
        /// ExemptField field type
        /// </summary>
        ExemptField,

        /// <summary>
        /// OutcomeChoice field type
        /// </summary>
        OutcomeChoice,

        /// <summary>
        /// PublishingCatalogSourceFieldType field type
        /// </summary>
        PublishingCatalogSourceFieldType,

        /// <summary>
        /// UserAgentSubstringsFieldType field type
        /// </summary>
        UserAgentSubstringsFieldType,

        /// <summary>
        /// ContentTypeId field type
        /// </summary>
        ContentTypeId,

        /// <summary>
        /// ContentTypeId field Type
        /// </summary>
        ContentTypeIdFieldType,

        /// <summary>
        /// Layoutsvariationfield
        /// </summary>
        LayoutVariationsField,
        
        /// <summary>
        /// ThreadIndex field
        /// </summary>
        ThreadIndex,

        /// <summary>
        /// 
        /// </summary>
        Facilities,

        FreeBusy,

        Overbook
    }

    /// <summary>
    /// This is the main class for creating the list templates. 
    /// </summary>
    /// <remarks>There has to be exactly one instance of this class for each contentTypes.xml file
    /// <seealso cref="SharePoint.ImportExport.Core.List"/> and <seealso cref="SharePoint.ImportExport.Core.ListOfItems"/>
    /// <example>
    /// <code>
    /// /* Create a new instance of the contentTypes class*/
    /// SharePoint.ImportExport.Core.ListOfContentTypes contentTypes= new ListOfContentTypes();
    /// <para></para>
    /// /* Create a new instance of the ListTemplate class and add it to the ListTemplate collection */
    /// ListTemplate listTemplate= new ListTemplate();
    /// contentTypes.contentTypes.Add(listTemplate);
    /// <para></para>
    /// listTemplate.NameAttribute="My Document Library";
    /// listTemplate.Name="My Document Library";
    /// listTemplate.Title="My Document Library";
    /// listTemplate.BaseType="DocumentLibrary";
    /// listTemplate.Description="My docs....";
    /// listTemplate.EnableAttachments=false;
    /// listTemplate.EnableVersioning=true;
    /// //Add a new custom field called MyField and add it fo the Fields collection
    /// <para></para>
    /// Field f=new Field();
    /// f.Name="MyField";
    /// f.Displayname="MyField";
    /// f.AddToDefaultView=true;
    /// f.ExtendedType=FieldType.Text;
    /// f.GroupBy=false;
    /// f.Required=false;
    /// f.Richtext=false;
    /// listTemplate.Fields.Add(f);
    /// <para></para>
    /// f=new Field();
    /// f.Name="MyUrlField";
    /// f.Displayname="MyUrlField";
    /// f.AddToDefaultView=true;
    /// f.ExtendedType=FieldType.URL;
    /// f.GroupBy=false;
    /// f.Required=false;
    /// f.Richtext=false;
    /// listTemplate.Fields.Add(f);
    /// <para></para>
    /// try
    ///  {
    ///   contentTypes.Serialize("listtemplates.xml");
    ///  }
    /// catch(SPExportException ex)
    ///  {
    ///   Console.WriteLine("Exception occurred: "+ex.Message);
    ///  }
    /// </code>
    /// </example>
    /// </remarks>
    [System.Xml.Serialization.XmlRootAttribute("listtemplates", Namespace = "", IsNullable = false)]
    public class ListOfContentTypes
    {
        /// <summary>
        /// internal list of content types
        /// </summary>
        private ContentTypeDefinitionCollection contentTypesList;

        /// <summary>
        /// This is the last error from the validation
        /// </summary>
        private string lastError;

        /// <summary>
        /// Initializes a new instance of the ListOfContentTypes class
        /// </summary>
        /// <remarks>Instantiates the ListTemplate member</remarks>
        public ListOfContentTypes()
        {
            this.contentTypesList = new ContentTypeDefinitionCollection();
        }

        /// <summary>
        /// Gets the last error from the validation
        /// </summary>
        public string LastError
        {
            get
            {
                return this.lastError;
            }
        }

        /// <summary>
        /// Gets  the list of list template nodes
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("listtemplate", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public ContentTypeDefinitionCollection ContentTypesCollection
        {
            get
            {
                return this.contentTypesList;
            }
        }

        /// <summary>
        /// This is the serialization function for the contentTypes class
        /// </summary>
        /// <param name="fileName">this is the name of the XML file that will be generated</param>
        /// <returns>true if succeeded</returns>
        /// <remarks>The method will throw as SPExportException if the data is invalid</remarks>
        public bool Serialize(string fileName)
        {
            string dirName = fileName;
            int pos = dirName.LastIndexOf("\\");
            if (pos > 0)
            {
                dirName = dirName.Substring(0, pos);
            }

            if (pos != -1)
            {
                if (!Directory.Exists(dirName))
                {
                    Directory.CreateDirectory(dirName);
                }
            }

            if (!this.Validate())
            {
                throw new SPExportException(this.LastError);
            }

            bool returnValue = true;

            using (StreamWriter exportListFile = new StreamWriter(fileName, false))
            {
                try
                {
                    XmlSerializer mySerializer = new XmlSerializer(typeof(SharePoint.ImportExport.Core.ListOfContentTypes));
                    mySerializer.Serialize(exportListFile, this);
                }
                catch (IOException inputOutputException)
                {
                    Console.WriteLine("Exception error: " + inputOutputException.Message);
                    SPExportException exportException = new SPExportException(inputOutputException.Message, inputOutputException);
                    throw exportException;
                }
                catch (Exception exception)
                {
                    Console.WriteLine("Exception error: " + exception.Message);
                    SPExportException exportException = new SPExportException(exception.Message, exception);
                    throw exportException;
                }
                finally
                {
                    exportListFile.Flush();
                    exportListFile.Close();
                }
            }

            return returnValue;
        }

        /// <summary>
        /// This is the validation method for the class
        /// </summary>
        /// <returns>true if data passes the validation</returns>
        public bool Validate()
        {
            bool returnValue = true;
            if (this.ContentTypesCollection == null)
            {
                returnValue = false;
                this.lastError = "The contentTypes.xml should contain at least one listtemplate node";
            }

            foreach (ContentTypeDefinition listTemplate in this.ContentTypesCollection)
            {
                try
                {
                    this.ValidateListTemplate(listTemplate);
                }
                catch (SPExportException ex)
                {
                    returnValue = false;
                    this.lastError = ex.Message;
                }
            }

            return returnValue;
        }

        /// <summary>
        /// Valiedates a field
        /// </summary>
        /// <param name="field">Field to be validated</param>
        private void ValidateField(Field field)
        {
            if (field.DisplayName == null)
            {
                throw new SPExportException("A field must have a displayname defined");
            }

            if (field.Name == null)
            {
                throw new SPExportException("A field must have a name defined");
            }

            if (field.ExtendedType == FieldType.Invalid)
            {
                throw new SPExportException("A field must have the extendedtype defined. For more info see the SPFieldType enumeration");
            }
        }

        /// <summary>
        /// This validates a content type
        /// </summary>
        /// <param name="contentType">Content type to validate</param>
        private void ValidateListTemplate(ContentTypeDefinition contentType)
        {
            if (contentType.Title == null)
            {
                throw new SPExportException("A listtemplate node must have a title");
            }

            if (contentType.Description == null)
            {
                throw new SPExportException("A listtemplate node must have a description");
            }

            if (contentType.Name == null)
            {
                throw new SPExportException("A listtemplate node must have a name");
            }

            if (contentType.BaseType == null)
            {
                throw new SPExportException("A listtemplate node must have a basetype (See SharePoint SDK for info on SPListTemplate)");
            }

            if (contentType.Fields != null)
            {
                foreach (Field field in contentType.Fields)
                {
                    try
                    {
                        this.ValidateField(field);
                    }
                    catch (SPExportException ex)
                    {
                        throw new SPExportException("Field validation in listtemplate " + contentType.Name + "failed. Error: " + ex.Message);
                    }
                }
            }
        }
    }

    /// <summary>
    /// This is the class implementing the contentTypes collection
    /// </summary>
    public class ContentTypeDefinitionCollection : ICollection
    {
        /// <summary>
        /// Internal list of content types
        /// </summary>
        private ArrayList listOfContentTypes;

        /// <summary>
        /// Initializes a new instance of the ContentTypesCollection class.
        /// </summary>
        /// <remarks>Instantiates the contentTypes member</remarks>    
        public ContentTypeDefinitionCollection()
        {
            this.listOfContentTypes = new ArrayList();
        }
        #region ICollection Members

        /// <summary>
        /// Gets a value indicating whether access to the ArrayList is synchronized (thread-safe).
        /// </summary>
        /// <remarks>
        /// To guarantee the thread safety of the ArrayList, all operations must be done through the wrapper returned by the Synchronized method.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public bool IsSynchronized
        {
            get
            {
                return this.listOfContentTypes.IsSynchronized;
            }
        }

        /// <summary>
        /// Gets a value indicating the number of objects in the collection. Read-only.
        /// </summary>
        public int Count
        {
            get
            {
                return this.listOfContentTypes.Count;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the ArrayList.
        /// </summary>
        /// <remarks>
        /// To create a synchronized version of the ArrayList, use the Synchronized method. However, derived classes can provide their own synchronized version of the ArrayList using the SyncRoot property. The synchronizing code must perform operations on the SyncRoot of the ArrayList, not directly on the ArrayList. This ensures proper operation of collections that are derived from other objects. 
        /// Specifically, it maintains proper synchronization with other threads that might be simultaneously modifying the ArrayList object.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or 
        /// catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public object SyncRoot
        {
            get
            {
                return this.listOfContentTypes.SyncRoot;
            }
        }

        #endregion

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">Index of item</param>
        public ContentTypeDefinition this[int index]
        {
            get
            {
                return (ContentTypeDefinition)this.listOfContentTypes[index];
            }
        }

        /// <summary>
        /// Copies the entire ListTemplate Array to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(ContentTypeDefinition[] a, int index)
        {
            this.listOfContentTypes.CopyTo(a, index);
        }

        /// <summary>
        /// Copies the entire ArrayList to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Array a, int index)
        {
            this.listOfContentTypes.CopyTo(a, index);
        }

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that can iterate through the ArrayList.
        /// </summary>
        /// <returns>The enumerator of the collection</returns>
        public IEnumerator GetEnumerator()
        {
            return this.listOfContentTypes.GetEnumerator();
        }

        #endregion
        /// <summary>
        /// Adds an object to the end of the ArrayList.
        /// </summary>
        /// <param name="newListTemplate">New ListTemplate to be added to the list</param>
        public void Add(ContentTypeDefinition newListTemplate)
        {
            this.listOfContentTypes.Add(newListTemplate);
        }
    }

    /// <summary>
    /// This is the class encapsulating a content type reference
    /// </summary>
    /// <remarks><seealso cref="SharePoint.ImportExport.Core.ListOfContentTypes"/></remarks>
    public class ContentTypeDefinition
    {
        /// <summary>
        /// This is the name of the content type
        /// </summary>
        private string name;

        /// <summary>
        /// This is the title of the content type
        /// </summary>
        private string title;

        /// <summary>
        /// This is the base type of the content type
        /// </summary>
        /// <remarks>
        /// Valid choices are
        /// <list type="bullet">
        /// <item>Announcements</item>
        /// <item>Contacts</item>
        /// <item>DiscussionBoard</item>
        /// <item>DocumentLibrary</item>
        /// <item>Events</item>
        /// <item>GenericList</item>
        /// <item>IssueTracking</item>
        /// <item>Links</item>
        /// <item>PictureLibrary</item>
        /// <item>Tasks</item>
        /// </list>
        /// </remarks>
        private string baseType;

        /// <summary>
        /// This is the description of the content type
        /// </summary>
        private string description;

        /// <summary>
        /// Boolean flag indicating whether or not the list supports attachments
        /// </summary>
        /// <remarks>Can only be true for lists</remarks>
        private bool enableAttachments;

        /// <summary>
        /// Boolean flag indicating whether or not the library supports versioning
        /// </summary>
        private bool enableVersioning;

        /// <summary>
        /// This is a list of the metadata fields
        /// </summary>
        private FieldsCollection fields;

        /// <summary>
        /// This is the list of the views 
        /// </summary>
        private ViewsCollection views;

        /// <summary>
        /// The name attribute of the list
        /// </summary>
        private string nameAttribute;

        /// <summary>
        /// This will contain all the extra properties not included in the xml schema
        /// </summary>
        private string propertyBag;

        /// <summary>
        /// This is the ID of the Content type
        /// </summary>
        /// <remarks></remarks>
        private string id;

        /// <summary>
        /// Initializes a new instance of the ContentType class.
        /// </summary>
        /// <remarks>Instantiates the Fields and Views members</remarks>
        public ContentTypeDefinition()
        {
            this.views = new ViewsCollection();
            this.fields = new FieldsCollection();
        }

        /// <summary>
        /// Gets or sets the name of the list template
        /// </summary>
        /// <remarks>This has to match the Name attribute in the ItemType class<seealso cref="SharePoint.ImportExport.Core.ItemsOfContentType"/></remarks>
        [System.Xml.Serialization.XmlElementAttribute("name", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Name
        {
            get
            {
                return this.name;
            }

            set
            {
                this.name = value;
            }
        }

        /// <summary>
        /// Gets or sets the title of the content type
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("Title", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Title
        {
            get
            {
                return this.title;
            }

            set
            {
                this.title = value;
            }
        }

        /// <summary>
        /// Gets or sets the basetype of the list/library
        /// </summary>
        /// <remarks>
        /// Valid choices are
        /// <list type="bullet">
        /// <item>Announcements</item>
        /// <item>Contacts</item>
        /// <item>DiscussionBoard</item>
        /// <item>DocumentLibrary</item>
        /// <item>Events</item>
        /// <item>GenericList</item>
        /// <item>IssueTracking</item>
        /// <item>Links</item>
        /// <item>PictureLibrary</item>
        /// <item>Tasks</item>
        /// </list>
        /// </remarks>
        [System.Xml.Serialization.XmlElementAttribute("BaseType", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string BaseType
        {
            get
            {
                return this.baseType;
            }

            set
            {
                this.baseType = value;
            }
        }

        /// <summary>
        /// Gets or sets the description of the list/library
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Description
        {
            get
            {
                return this.description;
            }

            set
            {
                this.description = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether or not the list supports attachments
        /// </summary>
        /// <remarks>Can only be true for lists</remarks>
        [System.Xml.Serialization.XmlElementAttribute("enableattachments", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public bool EnableAttachments
        {
            get
            {
                return this.enableAttachments;
            }

            set
            {
                this.enableAttachments = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether or not the library supports versioning
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("enableversioning", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public bool EnableVersioning
        {
            get
            {
                return this.enableVersioning;
            }

            set
            {
                this.enableVersioning = value;
            }
        }

        /// <summary>
        /// Gets a list of  metadata fields
        /// </summary>
        [System.Xml.Serialization.XmlArrayAttribute("fields", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [System.Xml.Serialization.XmlArrayItemAttribute("field", Form = System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable = false)]
        public FieldsCollection Fields
        {
            get
            {
                return this.fields;
            }
        }

        /// <summary>
        /// Gets the list of the views 
        /// </summary>
        [System.Xml.Serialization.XmlArrayAttribute("views", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [System.Xml.Serialization.XmlArrayItemAttribute("view", Form = System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable = false)]
        public ViewsCollection Views
        {
            get
            {
                return this.views;
            }
        }

        /// <summary>
        /// Gets or sets The name attribute of the list
        /// </summary>
        [System.Xml.Serialization.XmlAttributeAttribute("name")]
        public string NameAttribute
        {
            get
            {
                return this.nameAttribute;
            }

            set
            {
                this.nameAttribute = value;
            }
        }

        /// <summary>
        /// Gets or sets the value that will contain all the extra properties not included in the xml schema
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("propertyBag", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string PropertyBag
        {
            get
            {
                return this.propertyBag;
            }

            set
            {
                this.propertyBag = value;
            }
        }

        /// <summary>
        /// Gets or sets the ID of the Content type
        /// </summary>
        /// <remarks></remarks>
        [System.Xml.Serialization.XmlElementAttribute("ID", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string ContentTypeID
        {
            get
            {
                return this.id;
            }

            set
            {
                this.id = value;
            }
        }
    }

    /// <summary>
    /// This is the class implementing the Fields collection
    /// </summary>
    public class FieldsCollection : ICollection
    {
        /// <summary>
        /// Internal array of fields
        /// </summary>
        private ArrayList fields;

        /// <summary>
        /// Initializes a new instance of the FieldsCollection class
        /// </summary>
        /// <remarks>Instantiates the fields member</remarks>
        public FieldsCollection()
        {
            this.fields = new ArrayList();
        }
        #region ICollection Members

        /// <summary>
        /// Gets a value indicating whether access to the ArrayList is synchronized (thread-safe).
        /// </summary>
        /// <remarks>
        /// To guarantee the thread safety of the ArrayList, all operations must be done through the wrapper returned by the Synchronized method.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public bool IsSynchronized
        {
            get
            {
                return this.fields.IsSynchronized;
            }
        }

        /// <summary>
        /// Gets a value indicating the number of objects in the collection. Read-only.
        /// </summary>
        public int Count
        {
            get
            {
                return this.fields.Count;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the ArrayList.
        /// </summary>
        /// <remarks>
        /// To create a synchronized version of the ArrayList, use the Synchronized method. However, derived classes can provide their own synchronized version of the ArrayList using the SyncRoot property. The synchronizing code must perform operations on the SyncRoot of the ArrayList, not directly on the ArrayList. This ensures proper operation of collections that are derived from other objects. 
        /// Specifically, it maintains proper synchronization with other threads that might be simultaneously modifying the ArrayList object.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or 
        /// catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public object SyncRoot
        {
            get
            {
                return this.fields.SyncRoot;
            }
        }

        #endregion

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">Index of item</param>
        public Field this[int index]
        {
            get
            {
                return (Field)this.fields[index];
            }
        }

        /// <summary>
        /// Copies the entire Field Array to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Field[] a, int index)
        {
            this.fields.CopyTo(a, index);
        }

        /// <summary>
        /// Copies the entire ArrayList to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Array a, int index)
        {
            this.fields.CopyTo(a, index);
        }

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that can iterate through the ArrayList.
        /// </summary>
        /// <returns>The enumerator of the collection</returns>
        public IEnumerator GetEnumerator()
        {
            return this.fields.GetEnumerator();
        }

        #endregion

        /// <summary>
        /// Adds an object to the end of the ArrayList.
        /// </summary>
        /// <param name="newField">New Field to be added to the list</param>
        public void Add(Field newField)
        {
            this.fields.Add(newField);
        }
    }

    /// <summary>
    /// This is the class encapsulating the field that will be added to the list/library
    /// </summary>
    public class Field
    {
        /// <summary>
        /// This is the name of the field
        /// </summary>
        private string name;

        /// <summary>
        /// This is the displayname of the field
        /// </summary>
        private string displayname;

        /// <summary>
        /// Gets the type that the field extends
        /// </summary>
        /// <remarks>
        /// Valid types
        /// <list type="bullet">
        /// <item>Boolean</item>
        /// <item>Calculated</item>
        /// <item>Choice</item>
        /// <item>Currency</item>
        /// <item>DateTime</item>
        /// <item>Guid</item>
        /// <item>Integer</item>
        /// <item>Lookup</item>
        /// <item>MultiChoice</item>
        /// <item>Note</item>
        /// <item>Number</item>
        /// <item>Recurrence</item>
        /// <item>Text</item>
        /// <item>Threading</item>
        /// <item>URL</item>
        /// <item>User</item>
        /// </list>
        /// </remarks>
        private FieldType extendedtype;

        /// <summary>
        /// Boolean flag to indicate whether the field is mandatory or not
        /// </summary>
        private bool required;

        /// <summary>
        /// Boolean flag to indicate whether the field is added to the default view
        /// </summary>
        private bool addToDefaultView;

        /// <summary>
        /// Boolean flag to indicate whether the field is of type RichText
        /// </summary>
        private bool richtext;

        /// <summary>
        /// Boolean flag to indicate whether the field is used as a group by criteria
        /// </summary>
        private bool groupBy;

        /// <summary>
        /// This is the optional list of propertyvalues. Used when defining a choice type field
        /// </summary>
        private PropertyValuesCollection propertyValues;

        /// <summary>
        /// Field description in CAML
        /// </summary>
        private string xml;

        /// <summary>
        /// This controls the visibility of the field
        /// </summary>
        private bool hidden = false;

        /// <summary>
        /// This is the ID of the field
        /// </summary>
        private Guid id = Guid.NewGuid();

        /// <summary>
        /// Initializes a new instance of the Field class
        /// </summary>
        public Field()
        {
            this.propertyValues = new PropertyValuesCollection();
            this.extendedtype = FieldType.Invalid;
        }

        /// <summary>
        /// Gets or sets the name of the field
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("name", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Name
        {
            get
            {
                return this.name;
            }

            set
            {
                ////ToDo add validation
                this.name = value;
            }
        }

        /// <summary>
        /// Gets or sets the displayname of the field
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("displayname", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string DisplayName
        {
            get
            {
                return this.displayname;
            }

            set
            {
                this.displayname = value;
            }
        }

        /// <summary>
        /// Gets or sets the base type that the field is based on
        /// </summary>
        /// <remarks>
        /// Valid types
        /// <list type="bullet">
        /// <item>Boolean</item>
        /// <item>Calculated</item>
        /// <item>Choice</item>
        /// <item>Currency</item>
        /// <item>DateTime</item>
        /// <item>Guid</item>
        /// <item>Integer</item>
        /// <item>Lookup</item>
        /// <item>MultiChoice</item>
        /// <item>Note</item>
        /// <item>Number</item>
        /// <item>Recurrence</item>
        /// <item>Text</item>
        /// <item>Threading</item>
        /// <item>URL</item>
        /// <item>User</item>
        /// </list>
        /// </remarks>
        [System.Xml.Serialization.XmlElementAttribute("extended-type", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public FieldType ExtendedType
        {
            get
            {
                return this.extendedtype;
            }

            set
            {
                this.extendedtype = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the field is mandatory or not
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("required", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public bool Required
        {
            get
            {
                return this.required;
            }

            set
            {
                this.required = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the field is added to the default view
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("addtodefaultview", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public bool AddToDefaultView
        {
            get
            {
                return this.addToDefaultView;
            }

            set
            {
                this.addToDefaultView = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the field is of type RichText
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("richtext", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public bool Richtext
        {
            get
            {
                return this.richtext;
            }

            set
            {
                this.richtext = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the field is used as a group by criteria
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("groupby", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public bool GroupBy
        {
            get
            {
                return this.groupBy;
            }

            set
            {
                this.groupBy = value;
            }
        }

        /// <summary>
        /// Gets the optional list of propertyvalues. Used when defining a choice type field
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("propertyvalues", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public PropertyValuesCollection PropertyValues
        {
            get
            {
                return this.propertyValues;
            }
        }

        /// <summary>
        /// Gets or sets the field definition in CAML
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("schemaXML", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string CAML
        {
            get
            {
                return this.xml;
            }

            set
            {
                this.xml = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the field is visible or not
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("hidden", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public bool Hidden
        {
            get
            {
                return this.hidden;
            }

            set
            {
                this.hidden = value;
            }
        }

        /// <summary>
        /// Gets or sets the ID of the field
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("id", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public Guid ID
        {
            get
            {
                return this.id;
            }

            set
            {
                this.id = value;
            }
        }

    }

    /// <summary>
    /// This is the class implementing the PropertyValues collection
    /// </summary>
    public class PropertyValuesCollection : ICollection
    {
        /// <summary>
        /// Internal collection of properties
        /// </summary>
        private ArrayList propertyValues;

        /// <summary>
        /// Initializes a new instance of the PropertyValuesCollection class
        /// </summary>
        /// <remarks>Instantiates the PropertyValues member</remarks>
        public PropertyValuesCollection()
        {
            this.propertyValues = new ArrayList();
        }
        #region ICollection Members

        /// <summary>
        /// Gets a value indicating whether access to the ArrayList is synchronized (thread-safe).
        /// </summary>
        /// <remarks>
        /// To guarantee the thread safety of the ArrayList, all operations must be done through the wrapper returned by the Synchronized method.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public bool IsSynchronized
        {
            get
            {
                return this.propertyValues.IsSynchronized;
            }
        }

        /// <summary>
        /// Gets a value indicating the number of objects in the collection. Read-only.
        /// </summary>
        public int Count
        {
            get
            {
                return this.propertyValues.Count;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the ArrayList.
        /// </summary>
        /// <remarks>
        /// To create a synchronized version of the ArrayList, use the Synchronized method. However, derived classes can provide their own synchronized version of the ArrayList using the SyncRoot property. The synchronizing code must perform operations on the SyncRoot of the ArrayList, not directly on the ArrayList. This ensures proper operation of collections that are derived from other objects. 
        /// Specifically, it maintains proper synchronization with other threads that might be simultaneously modifying the ArrayList object.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or 
        /// catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public object SyncRoot
        {
            get
            {
                return this.propertyValues.SyncRoot;
            }
        }

        #endregion

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">Index of item</param>
        public string this[int index]
        {
            get
            {
                return (string)this.propertyValues[index];
            }
        }

        /// <summary>
        /// Copies the entire string Array to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(string[] a, int index)
        {
            this.propertyValues.CopyTo(a, index);
        }

        /// <summary>
        /// Copies the entire ArrayList to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Array a, int index)
        {
            this.propertyValues.CopyTo(a, index);
        }

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that can iterate through the ArrayList.
        /// </summary>
        /// <returns>The enumerator of the collection</returns>
        public IEnumerator GetEnumerator()
        {
            return this.propertyValues.GetEnumerator();
        }

        #endregion

        /// <summary>
        /// Adds an object to the end of the ArrayList.
        /// </summary>
        /// <param name="newPropertyValue">New PropertyValues to be added to the list</param>
        public void Add(string newPropertyValue)
        {
            this.propertyValues.Add(newPropertyValue);
        }
    }

    /// <summary>
    /// This is the class implementing the Views collection
    /// </summary>
    public class ViewsCollection : ICollection
    {
        /// <summary>
        /// Thios is the internal collection of views
        /// </summary>
        private ArrayList views;

        /// <summary>
        /// Initializes a new instance of the ViewsCollection class
        /// </summary>
        /// <remarks>Instantiates the views member</remarks>
        public ViewsCollection()
        {
            this.views = new ArrayList();
        }
        #region ICollection Members

        /// <summary>
        /// Gets a value indicating whether access to the ArrayList is synchronized (thread-safe).
        /// </summary>
        /// <remarks>
        /// To guarantee the thread safety of the ArrayList, all operations must be done through the wrapper returned by the Synchronized method.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public bool IsSynchronized
        {
            get
            {
                return this.views.IsSynchronized;
            }
        }

        /// <summary>
        /// Gets  a value indicating the number of objects in the collection. Read-only.
        /// </summary>
        public int Count
        {
            get
            {
                return this.views.Count;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the ArrayList.
        /// </summary>
        /// <remarks>
        /// To create a synchronized version of the ArrayList, use the Synchronized method. However, derived classes can provide their own synchronized version of the ArrayList using the SyncRoot property. The synchronizing code must perform operations on the SyncRoot of the ArrayList, not directly on the ArrayList. This ensures proper operation of collections that are derived from other objects. 
        /// Specifically, it maintains proper synchronization with other threads that might be simultaneously modifying the ArrayList object.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or 
        /// catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public object SyncRoot
        {
            get
            {
                return this.views.SyncRoot;
            }
        }

        #endregion

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">Index of item</param>
        public View this[int index]
        {
            get
            {
                return (View)this.views[index];
            }
        }

        /// <summary>
        /// Copies the entire View array to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(View[] a, int index)
        {
            this.views.CopyTo(a, index);
        }

        /// <summary>
        /// Copies the entire ArrayList to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Array a, int index)
        {
            this.views.CopyTo(a, index);
        }

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that can iterate through the ArrayList.
        /// </summary>
        /// <returns>The enumerator of the collection</returns>
        public IEnumerator GetEnumerator()
        {
            return this.views.GetEnumerator();
        }

        #endregion
        /// <summary>
        /// Adds an object to the end of the ArrayList.
        /// </summary>
        /// <param name="newView">New View to be added to the list</param>
        public void Add(View newView)
        {
            this.views.Add(newView);
        }
    }

    /// <summary>
    /// This is the class encapsulating the view
    /// </summary>
    public class View
    {
        /// <summary>
        /// This is the view name
        /// </summary>
        private string name;

        /// <summary>
        /// Boolean flag to indicate whether the view will become the default view
        /// </summary>
        private bool defaultView;

        /// <summary>
        /// Boolean value that specifies whether the view is hidden.
        /// </summary>
        private bool hidden;

        /// <summary>
        /// This is the query specified in CAML
        /// </summary>
        private string query;

        /// <summary>
        ///  This is the collection of the fields in the view
        /// </summary>
        private StringCollection viewFields;

        /// <summary>
        ///  This is the view type
        /// </summary>
        private string viewType = "Html";

        /// <summary>
        /// Initializes a new instance of the View class
        /// </summary>
        public View()
        {
            this.viewFields = new StringCollection();
        }

        /// <summary>
        /// Gets or sets the view name
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("name", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Name
        {
            get
            {
                return this.name;
            }

            set
            {
                this.name = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the view will become the default view
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("defaultview", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public bool DefaultView
        {
            get
            {
                return this.defaultView;
            }

            set
            {
                this.defaultView = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the view is a hidden view
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("hidden", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public bool Hidden
        {
            get
            {
                return this.hidden;
            }

            set
            {
                this.hidden = value;
            }
        }

        /// <summary>
        /// Gets or sets the query specified in CAML
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("query", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Query
        {
            get
            {
                return this.query;
            }

            set
            {
                this.query = value;
            }
        }

        /// <summary>
        /// Gets the collection of the fields in the view
        /// </summary>
        [System.Xml.Serialization.XmlArrayAttribute("viewfields", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [System.Xml.Serialization.XmlArrayItem("name", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public StringCollection ViewFields
        {
            get
            {
                return this.viewFields;
            }
        }

        /// <summary>
        /// Gets or sets the view type
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("type", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string ViewType
        {
            get
            {
                return this.viewType;
            }

            set
            {
                this.viewType = value;
            }
        }


    }

    /// <summary>
    /// This class implements the viewfields functionality
    /// </summary>
    public class ViewField
    {
        /// <summary>
        /// This is the view filed name
        /// </summary>
        private string name;

        /// <summary>
        /// Initializes a new instance of the ViewField class.
        /// </summary>
        /// <param name="field">View field name</param>
        public ViewField(string field)
        {
            this.name = field;
        }

        /// <summary>
        /// Gets or sets the view field name
        /// </summary>
        public string Name
        {
            get
            {
                return this.name;
            }

            set
            {
                this.name = value;
            }
        }
    }
}
